package com.mall.common.service.impl;

import static com.mall.common.Constants.OPERATE_TYPE_NORMAL;

import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.mall.common.dao.MenuDao;
import com.mall.common.domain.manage.Menu;
import com.mall.common.domain.manage.Menu.MenuType;
import com.mall.common.domain.manage.Operate;
import com.mall.common.hibernate.Finder;
import com.mall.common.service.MenuService;
import com.mall.common.service.OperateService;

/**
 * Service实现类 - 资源
 */

@Service
@Transactional(readOnly=true)
public class MenuServiceImpl extends BaseServiceImpl<Menu, Long> implements MenuService {
	
	@Resource private OperateService operateService;
	
	@Resource
	public void setBaseDao(MenuDao menDao) {
		super.setBaseDao(menDao);
	}

	@Override
	public List<Menu> getTopList() {
		List<Menu> menuList = this.getTopList(true);
		return menuList;
	}
	
	@Override
	public List<Menu> getTopListByRigth() {
		//获取角色
		List<Menu> menuList = this.getTopListByRigth(null);
		return menuList;
	}
	
	@Override
	public List<Menu> getAllMenus(){
		String hql = "from Menu bean order by bean.priority";
		Finder f = Finder.create(hql);
		List<Menu> menus = f.findHQLList();
		return menus;
	}
	
	public List<Menu> getMenuTree(List<Long> roleIds) {
		Finder finder = Finder.create("select distinct m from Menu m");
		if(roleIds != null && roleIds.size() > 0){
			finder.append(" join m.roleSet r");
		}
		if(roleIds != null && roleIds.size() > 0){
			finder.append(" where r.id in (:roleIds)");
			finder.setParamList("roleIds", roleIds.toArray());
		}
		finder.append(" order by m.priority asc,m.id asc");
		return finder.findHQLList();
	}

	@Transactional(propagation=Propagation.REQUIRED)
	public Menu update(Menu menu, Operate operate) {
		menu = this.updateByUpdater(menu);
		if(MenuType.MENUTYPE_NODE.equals(menu.getType())){
			operateService.updateByUpdater(operate);
		}
		return menu;
		
	}
	
	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void save(Menu menu, Operate operate){
		if(MenuType.MENUTYPE_LINE.equals(menu.getType())){
			menu.setName("-- 分隔线 --");
		}
		
		//sort order
		if(menu.getPriority() == null){
			Finder f = null;
			if(menu.getUpDomain() == null){
				f = Finder.create("select max(bean.priority) from Menu bean where bean.upDomain is null");
			}else{
				f = Finder.create("select max(bean.priority) from Menu bean where bean.upDomain=:upDomain");
				f.setParam("upDomain", menu.getUpDomain());
			}
			Integer max = (Integer)f.findUniqueByHQL();
			menu.setPriority(max == null ? 1 : max + 1);
		}
		persist(menu);
		if(MenuType.MENUTYPE_NODE.equals(menu.getType())){
			operate.setType(OPERATE_TYPE_NORMAL);
			operate.setMenu(menu);
			operate.setName("菜单所属动作");
			operateService.persist(operate);
			menu.setOperate(operate);
		}
	}
	
	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void updateMoveMenu(Menu menu, int i) {
		
		//获取子节点最大或最小的节点
		Finder f = Finder.create("select bean from Menu bean where");
		if(menu.getUpDomain() != null && menu.getUpDomain().getId() != null){
			f.append(" bean.upDomain=:upDomain and ");
			f.setParam("upDomain", menu.getUpDomain());
		}
		f.append(" bean.priority=");
		//下移
		if (i == 1) {
			f.append("(select min(m.priority) from Menu m where m.priority>:up_priority)");
		} else if (i == -1) {
			f.append("(select max(m.priority) from Menu m where m.priority<:up_priority");
		}
		f.setParam("up_priority", menu.getPriority());
		if(menu.getUpDomain() != null && menu.getUpDomain().getId() != null){
			f.append(" and m.upDomain=:upDomain");
			f.setParam("upDomain", menu.getUpDomain());
		}
		f.append(")");
		Menu neibMenu = (Menu)f.findUniqueByHQL();
		
		if(neibMenu != null){
			Integer cur_menu_priority = menu.getPriority();
			menu.setPriority(neibMenu.getPriority());
			neibMenu.setPriority(cur_menu_priority);
		}
	}
	
	public List<Menu> getTopList(boolean displayOnly){
		Finder f = getTopFinder(displayOnly);
		return f.findHQLList();
	}
	
	@SuppressWarnings({ "rawtypes"})
	private List<Menu> getTopListByRigth(Set roles) {
		Finder f = Finder.create("select bean from Menu bean");
		f.append(" join bean.roleSet role");
		f.append(" where roleSet in (:roles)");
		f.setParamList("roles", roles);
		f.append(" and bean.parent.id is null");
		f.append(" order by bean.priority asc,bean.id asc");
		return f.findHQLList();
	}
			
	private Finder getTopFinder(boolean displayOnly) {
		Finder f = Finder.create("from Menu bean");
		f.append(" where bean.upDomain.id is null");
		f.append(" order by bean.priority");
		return f;
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void updateMenuPriority(Long[] ids, Integer[] priority){
		for (int i = 0, len = ids.length; i < len; i++) {
			Menu menu = this.find(ids[i]);
			menu.setPriority(priority[i]);
		}
	}

	@Override
	@CacheEvict(value="authorization",allEntries=true)
	@Transactional(propagation=Propagation.REQUIRED)
	public void persist(Menu entity) {
		super.persist(entity);
	}

	@Override
	@CacheEvict(value="authorization",allEntries=true)
	@Transactional(propagation=Propagation.REQUIRED)
	public Menu update(Menu entity) {
		return super.update(entity);
	}

	@Override
	@CacheEvict(value="authorization",allEntries=true)
	@Transactional(propagation=Propagation.REQUIRED)
	public void remove(Long id) {
		super.remove(id);
	}
	
	@Override
	@CacheEvict(value="authorization",allEntries=true)
	@Transactional(propagation=Propagation.REQUIRED)
	public Menu updateByUpdater(Menu entity){
		return super.updateByUpdater(entity);
	}
}